// by Wei Pan

#include <iostream>
using namespace std;

struct T {
    virtual T& operator+(const T& t);
};

struct T1 : public T {
    float val;
    T1 (float v) : val(v) {}
    T1& operator+(const T1 &t) {
        cout << "T1 +" << endl;
        val += (1 + t.val);
        return *this;
    }
};

struct T2 : public T {
    int val;
    T2 (int v) : val(v) {}
    T2& operator+(const T2 &t) {
        cout << "T2 +" << endl;
        val += (2 + t.val);
        return *this;
    }
};

T& T::operator+(const T& t)
{
    try {
        T1& myself = dynamic_cast<T1&>(*this);
        const T1& other = dynamic_cast<const T1&>(t);
        return myself + other;
    } catch (std::bad_cast&) { }

    try {
        T2& myself = dynamic_cast<T2&>(*this);
        const T2& other = dynamic_cast<const T2&>(t);
        return myself + other;
    } catch (std::bad_cast&) { }

    cout << "T + not implemented" << endl;
    return *this;
}

ostream& operator<<(ostream& os, const T& t) {
	try {
        const T1& myself = dynamic_cast<const T1&>(t);
		cout << myself.val;
    } catch (std::bad_cast&) { }

    try {
        const T2& myself = dynamic_cast<const T2&>(t);
		cout << myself.val;
    } catch (std::bad_cast&) { }

	return os; // foget this, get a segmentation fault

}
ostream& operator<<(ostream& os, const T1& t) {
    cout << t.val;
    return os; 
}

ostream& operator<<(ostream& os, const T2& t) {
    cout << t.val;
    return os; 
}


int main()
{
    T1 a(1.1);
    T1 b(2.2);
    T2 c(3);
    T2 d(4);

    T *pa = &a; 
    T *pb = &b; 
    T *pc = &c; 
    T *pd = &d;

    cout << "a = " << a << endl;
    cout << "b = " << b << endl;
    cout << "a + b = " << (*pa) + (*pb) << endl;
    cout << "a = " << a << endl;
    cout << "b = " << b << endl;
    
    cout << "++++++++++++++++++++++++++++++++++++" << endl;

    cout << "c = " << c << endl;
    cout << "d = " << d << endl;
    cout << "c + d = " << (*pc) + (*pd) << endl;
    cout << "c = " << c << endl;
    cout << "d = " << d << endl;

    return 0;
}
